package xiaoa.java.mongoDB;

import com.mongodb.BasicDBObject;
import com.mongodb.MongoClient;

import com.mongodb.ServerAddress;
import com.mongodb.client.FindIterable;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoCursor;
import com.mongodb.client.MongoDatabase;
import com.mongodb.client.model.Aggregates;
import com.mongodb.client.model.BsonField;
import com.mongodb.client.model.Filters;
import com.mongodb.client.model.Projections;

import org.bson.Document;
import org.bson.conversions.Bson;
import org.bson.types.ObjectId;

import xiaoa.java.log.L;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

import javax.persistence.Id;

/**
 * Created by xiaoa on 2017/2/26.
 */
public class DbMgr {

    // MongoDB client
    private static MongoClient  mongoClient =  null;

    // MongoDB MongoDatabase
    private static MongoDatabase  database = null;

    public static void init(String host , int port){

        if (mongoClient == null){

            // 创建一个链接地址
            ServerAddress  address = new ServerAddress( host , port);

            mongoClient = new MongoClient(address);
            L.info("============= 链接始化成功");
        }

    }

    /**
     * 获取client
     * @return
     * @throws Throwable
     */
    private static MongoClient  getMongoClient()throws  Throwable{

        if (mongoClient == null ){
            throw  new RuntimeException("NOT INIT");
        }

        return mongoClient;

    }


    /**
     * 获取数据库链接
     * @param databaseName
     * @throws Throwable
     */
    public static void initDatabase(String databaseName)throws  Throwable{

        if (databaseName == null || databaseName.equals("")){
            throw  new RuntimeException("参数有误！");
        }

        if (database != null){
            return ;
        }

        // 获取数据库链接
        MongoDatabase  mongoDatabase = getMongoClient().getDatabase(databaseName);

        database = mongoDatabase;

        L.info("============ 数据库初始化成功");

    }

    /**
     * 获取数据库
     */
    public static MongoDatabase getDatabase(){

        if (database == null){
            throw  new RuntimeException("数据库未初始化");
        }

        return database;

    }


    /**
     * 创建一个集合（table）
     * @param collectionName
     * @throws Throwable
     */
    public static void createCollection(String collectionName)throws Throwable {

        if  (collectionName == null || collectionName.equals("")){
            throw  new RuntimeException("参数有误");
        }

        getDatabase().createCollection(collectionName);

    }


    /**
     * 获取集合(table)
     * @param collectionName
     * @return
     * @throws Throwable
     */
    public static MongoCollection<Document>   getMongoCollection(String collectionName )throws  Throwable{

        return getDatabase().getCollection(collectionName );

    }


    
    /**
     * 修改
     * @Title: update
     * @param obj
     * @param collectionName
     * @throws Throwable
     * @author xiaoa
     */
    public static long updateMany(Object  obj  , Bson query  , Class<?> cla)throws  Throwable{
    	
    	 // 获取集合
        MongoCollection<Document>   mongoCollection  = getMongoCollection(DbUtils.getCollectionName(cla));
        return  mongoCollection.updateMany(query, new Document("$set", DbUtils.objToDocument(obj))).getMatchedCount();
       
    }
    
    
    /**
     * 修改
     * @Title: updateOne
     * @param obj
     * @param id
     * @param cla
     * @throws Throwable
     * @author xiaoa
     */
    public static void update(Object  obj , String id , Class<?> cla)throws  Throwable{
    	
   	 // 获取集合
       MongoCollection<Document>   mongoCollection  = getMongoCollection(DbUtils.getCollectionName(cla));
       mongoCollection.updateMany(Filters.eq("_id", new ObjectId(id)), new Document("$set", DbUtils.objToDocument(obj)));
   }
    
    
   
    
   /**
    * 保存
    * @Title: save
    * @param id  shujuid
    * @param value
    * @param query
    * @param cla
    * @throws Throwable
    * @author xiaoa
    */
    public static void save(String id , Object doc , Class<?> cla )throws  Throwable{
    	
   	 // 获取集合
       MongoCollection<Document>   mongoCollection  = getMongoCollection(DbUtils.getCollectionName(cla) );
       
      mongoCollection.findOneAndReplace(Filters.eq("_id", id), DbUtils.objToDocument(doc));
       
   }
    
    
   /**
    * 插入单条数据
    * @Title: insertOne
    * @param document
    * @param id
    * @param cla
    * @throws Throwable
    * @author xiaoa
    */
    public static  void insertOne( Object  doc ,  Class<?> cla )throws  Throwable{

        if (doc == null || cla == null){
            throw  new RuntimeException("参数有误");
        }

        // 获取集合
        MongoCollection<Document>   mongoCollection  = getMongoCollection( DbUtils.getCollectionName(cla) );

        // 创建集合描述文件
        mongoCollection.insertOne(DbUtils.objToDocument(doc) );
    }
    
    
    /**
     * 插入多个
     * @Title: insertMany
     * @param list
     * @param cla
     * @throws Throwable
     * @author xiaoa
     */
    public static  int insertMany( List<?>  list ,  Class<?> cla )throws  Throwable{

        if (list == null || list.isEmpty() || cla == null){
            throw  new RuntimeException("参数有误");
        }
        
        long startTime = System.currentTimeMillis();

        // 获取集合
        MongoCollection<Document>   mongoCollection  = getMongoCollection( DbUtils.getCollectionName(cla) );

        // 创建集合描述文件
        mongoCollection.insertMany(DbUtils.objToDocumentList(list));
        
        L.info(startTime, System.currentTimeMillis(), "insertMany");
        
        return list.size();
    }
    
    
    /**
     * 计算数量
     * @Title: count
     * @param query
     * @return
     * @author xiaoa
     */
    public static long count(Class<?> cla , Bson query )throws  Throwable{

        // 获取集合
        MongoCollection<Document>   mongoCollection  = getMongoCollection( DbUtils.getCollectionName(cla) );
        
        List<Bson>  pipeline = new LinkedList<>();
        if (query != null){
        	pipeline.add(Aggregates.match(query)) ; //设置条件
        }
        pipeline.add(Aggregates.group(null, new BsonField("count", new BasicDBObject("$sum", 1) )));
        MongoCursor<Document> cursor =   mongoCollection.aggregate(pipeline).iterator();
        
        long count = 0;
        
        // 数据游标
    	while (cursor.hasNext()){
    		
    		Document  doc =	cursor.next();
    		count = Long.valueOf(doc.get("count").toString());
    	}
        
    	return count;
        
    }
    
    /**
     * 查询
     * @Title: search
     * @param cla
     * @param query
     * @param sort
     * @param page
     * @param pageSize
     * @return
     * @throws Throwable
     * @author xiaoa
     */
    public static <TT> List<TT>  search(Class<TT> cla , Bson query  ,Bson sort  , int page , int pageSize)throws  Throwable{
    
    	return search(cla, query, sort, null, page, pageSize);
    	
    }


   /**
    * 查询
    * @Title: search
    * @param cla
    * @param query
    * @param sort
    * @param fieldNameList
    * @param page
    * @param pageSize
    * @return
    * @throws Throwable
    * @author xiaoa
    */
    public static <TT> List<TT>  search(Class<TT> cla , Bson query  ,Bson sort , List<String> fieldNameList  , int page , int pageSize)throws  Throwable{

    	long startTime = System.currentTimeMillis();
    	
        // 创建一个集合
        List<TT> list = new ArrayList<TT>();

        // 获取集合
        MongoCollection<Document>   mongoCollection  = getMongoCollection( DbUtils.getCollectionName(cla) );

        FindIterable<Document>  findIterable = mongoCollection.find( query ).skip((page -1) * pageSize ).limit(pageSize);
        
        // 设置排序
        if (sort != null ){
        	findIterable.sort(sort);
        }
        
        // 如果有设置字段
        if (fieldNameList != null && fieldNameList.size() > 0){
        	findIterable.projection(Projections.include(fieldNameList));
        }

        // 数据游标
        MongoCursor<Document> cursor = findIterable.iterator();

        while (cursor.hasNext()){

        	TT obj = DbUtils.docToObj(cla, cursor.next());
        
            // 将对象添加到集合中
            if (obj != null){
                list.add(obj);
            }
        }
        
        L.info(startTime, System.currentTimeMillis(), "search [" + list.size() + "]");

        return list;

    }




    public static void main(String[] args)throws  Throwable{


        // 初始化数据库
        init("xiaoa", 27017);
        initDatabase("xiaoaDome");

        // 创建一个对象
        TestVo vo  = new TestVo();
        vo.userName = "小a";
        vo.password = "123456新加";
        vo.age       = "12";

//        insertOne(vo ,TestVo.class );

        L.info("============== 插入成功");

        // 获取集合
//        List<TestVo>  list = search(TestVo.class , Filters.eq("userName", "小a"),0 , 2);

//        L.info("==================== list = " + com.alibaba.fastjson.JSON.toJSONString(list));
        
        
        vo.setUserName("小a");
        vo.setPassword("2121修改");
        vo.setAge("11修改");
        
        System.out.println( TestVo.class.getSimpleName());
        
//        updateMany(vo, Filters.eq("userName", "小a"),  TestVo.class.getSimpleName() );
        
        // 获取集合
        List<TestVo>  listq = search(TestVo.class , Filters.eq("_id", new ObjectId("59d9a48b7dc3063e988715a9")),null,0 , 100);

        L.info("==================== list = " + com.alibaba.fastjson.JSON.toJSONString(listq));
        
        
        System.out.println(count(TestVo.class, Filters.eq("userName", "小a")));
        
        
        System.out.println("修改成功");
        

    }


    /**
     * 测试vo
     */
    public static class TestVo {

    	
    	@Id
    	public String id;
    	
        // 用户名
        public String userName;

        // 密码
        public  String password;

        // 年龄
        public  String age;


        public String getUserName() {
            return userName;
        }

        public void setUserName(String userName) {
            this.userName = userName;
        }

        public String getPassword() {
            return password;
        }

        public void setPassword(String password) {
            this.password = password;
        }

        public String getAge() {
            return age;
        }

        public void setAge(String age) {
            this.age = age;
        }
    }



}
